#include "nodoejercicio.h"
#include "asistentexml.h"
#include "entrenador.h"

NodoEjercicio::NodoEjercicio()
{
    indiceNodoHijo = 0;
}

NodoEjercicio::~NodoEjercicio()
{
    foreach (NodoEjercicio* nodoHijo, listaNodosHijos) {
        delete nodoHijo;
    }
}

void NodoEjercicio::iniciar()
{
    iniciarHijos();
}

void NodoEjercicio::iniciarHijos()
{
    indiceNodoHijo = 0;
    foreach (NodoEjercicio* nodoHijo, listaNodosHijos) {
        nodoHijo->iniciar();
    }
}

bool NodoEjercicio::tieneHijos()
{
    return !listaNodosHijos.isEmpty();
}

Patron NodoEjercicio::getSiguientePatron()
{
    if (indiceNodoHijo >= listaNodosHijos.size()) {
        return Patron();
    }
    
    if (listaNodosHijos[indiceNodoHijo]->haTerminado()) {
        indiceNodoHijo++;
    }

    if (indiceNodoHijo >= listaNodosHijos.size()) {
        return Patron();
    }

    Patron patron = listaNodosHijos[indiceNodoHijo]->getSiguientePatron();
    return patron;    
}

bool NodoEjercicio::haTerminado()
{
    return hanTerminadoHijos();
}

bool NodoEjercicio::hanTerminadoHijos()
{
    if (indiceNodoHijo >= listaNodosHijos.size()) {
        return true;
    } else if (indiceNodoHijo == listaNodosHijos.size() - 1) {
        return listaNodosHijos[indiceNodoHijo]->haTerminado();
    }

    return false;
}

void NodoEjercicio::agregarNodo(NodoEjercicio* nodo)
{
    listaNodosHijos.append(nodo);
}

void NodoEjercicio::deserializar(const QDomElement& elementoEjercicio, Proyecto* proyecto)
{
    AsistenteXml asistente(elementoEjercicio.ownerDocument());

    QList<QDomElement> listaElementosHijos = asistente.leerElementos(elementoEjercicio, "");
    foreach (QDomElement elementoHijo, listaElementosHijos) {
        QString tag = elementoHijo.tagName();
         NodoEjercicio* nodoHijo = NULL;
        if (tag == "ejecucion") {
            nodoHijo = new NodoEjecucion();
        } else if (tag == "iteracion") {
            nodoHijo = new NodoIteracion();
        } else if (tag == "duracion") {
            nodoHijo = new NodoDuracion();
        } else if (tag == "cambio-tempo") {
            nodoHijo = new NodoCambioTempo();
        }
        if (nodoHijo != NULL) { 
            nodoHijo->deserializar(elementoHijo, proyecto);
            listaNodosHijos.append(nodoHijo);
        }
    }
}


NodoEjecucion::NodoEjecucion()
{
    indicePatron = 0;
}
//
//NodoEjecucion::~NodoEjecucion()
//{
//
//}

void NodoEjecucion::agregarPatron(const Patron& patron)
{
    listaPatrones.append(patron); 
}

bool NodoEjecucion::haTerminado()
{
    return indicePatron >= listaPatrones.size();
}


void NodoEjecucion::iniciar()
{
    //qDebug() << "Inicio de ejecucion ";
    indicePatron = 0;
    iniciarHijos();
}

Patron NodoEjecucion::getSiguientePatron()
{   
    if (indicePatron >= listaPatrones.size()) {
        return Patron();
    }

    Patron patronEjecucion = listaPatrones[indicePatron];
    Patron patronEjercicio = NodoEjercicio::getSiguientePatron();

    if (!tieneHijos()) {
        indicePatron++;
    } else if (hanTerminadoHijos()) {
        indicePatron++;
        iniciarHijos();
    }

    return Patron::solapar(patronEjecucion, patronEjercicio);
}

void NodoEjecucion::deserializar(const QDomElement& elementoEjercicio, Proyecto* proyecto)
{
    AsistenteXml asistente(elementoEjercicio.ownerDocument());

    QString mascaraCompas = asistente.leerAtributo(elementoEjercicio, "compas");
    if (!mascaraCompas.isEmpty()) {
        QList<Compas> listaCompases = proyecto->getCompases(mascaraCompas);
        foreach (Compas compas, listaCompases) {
            listaPatrones.append(Patron(compas));
        }
    } else {
        QString mascaraPatron = asistente.leerAtributo(elementoEjercicio, "patron");
        listaPatrones = proyecto->getPatrones(mascaraPatron);
    }
    indicePatron = 0;

    NodoEjercicio::deserializar(elementoEjercicio, proyecto);
}

NodoIteracion::NodoIteracion()
{
    iteraciones = -1;
    contador = 0;
}


void NodoIteracion::setIteraciones(int iteraciones)
{
    this->iteraciones = iteraciones;
}

void NodoIteracion::iniciar()
{
    contador = 0;
    iniciarHijos();
}

Patron NodoIteracion::getSiguientePatron()
{
    if (haTerminado()) {
        return Patron();
    }

    if (hanTerminadoHijos()) {
        contador++;
        if (haTerminado()) {
            return Patron();
        }
        iniciarHijos();        
    }

    Patron patron = NodoEjercicio::getSiguientePatron();
    return patron;
}

bool NodoIteracion::haTerminado()  
{
    return iteraciones >= 0 && contador >= iteraciones;
}

void NodoIteracion::deserializar(const QDomElement& elementoEjercicio, Proyecto* proyecto)
{
    AsistenteXml asistente(elementoEjercicio.ownerDocument());
   
    QString cadenaIteraciones = asistente.leerAtributo(elementoEjercicio, "iteraciones");
    if (!cadenaIteraciones.isEmpty()) {
        iteraciones = cadenaIteraciones.toInt();
    }

    NodoEjercicio::deserializar(elementoEjercicio, proyecto);
}

NodoDuracion::NodoDuracion()
{
    minutos = 0;
}

void NodoDuracion::setMinutos(int minutos)
{
    this->minutos = minutos;
}

void NodoDuracion::iniciar()
{
    contadorTiempo.inicializar();
    NodoEjercicio::iniciar();
}

Patron NodoDuracion::getSiguientePatron()
{
    if (haTerminado()) {
        return Patron();
    }

    if (hanTerminadoHijos()) {        
        iniciarHijos();
    }

    Patron patron = NodoEjercicio::getSiguientePatron();
    return patron;
}

bool NodoDuracion::haTerminado()
{
    int segundosTranscurridos = contadorTiempo.getSegundosTranscurridos();
    return segundosTranscurridos >= segundos + minutos * 60;
}

void NodoDuracion::deserializar(const QDomElement& elementoEjercicio, Proyecto* proyecto)
{
    AsistenteXml asistente(elementoEjercicio.ownerDocument());
   
    minutos = asistente.leerAtributo(elementoEjercicio, "minutos").toInt();
    segundos = asistente.leerAtributo(elementoEjercicio, "segundos").toInt();

    NodoEjercicio::deserializar(elementoEjercicio, proyecto);
}

NodoCambioTempo::NodoCambioTempo()
{
    tempoInicial = 0;
    tempoFinal = 0;
    incrementoTempo = 0;
}

void NodoCambioTempo::iniciar()
{
    tempoActual = tempoInicial;
    Entrenador::getInstancia()->setTempo(tempoActual);
    NodoEjercicio::iniciar();
}

Patron NodoCambioTempo::getSiguientePatron()
{
    if (haTerminado()) {
        return Patron();
    }

    if (hanTerminadoHijos()) {
        tempoActual += incrementoTempo;
        if (haTerminado()) {
            return Patron();
        }
        Entrenador::getInstancia()->setTempo(tempoActual);
        
        iniciarHijos();  
    }

    Patron patron = NodoEjercicio::getSiguientePatron();
    return patron;
}

bool NodoCambioTempo::haTerminado()
{
    return tempoActual + incrementoTempo > tempoFinal;
}


void NodoCambioTempo::setRango(int tempoInicial, int tempoFinal, int incrementoTempo)
{
    this->tempoInicial = tempoInicial;
    this->tempoFinal = tempoFinal;
    this->incrementoTempo = incrementoTempo;
}

void NodoCambioTempo::deserializar(const QDomElement& elementoEjercicio, Proyecto* proyecto)
{
    AsistenteXml asistente(elementoEjercicio.ownerDocument());
   
    tempoInicial = asistente.leerAtributo(elementoEjercicio, "tempo-inicial").toInt();
    tempoFinal = asistente.leerAtributo(elementoEjercicio, "tempo-final").toInt();
    incrementoTempo = asistente.leerAtributo(elementoEjercicio, "incremento-tempo").toInt();

    NodoEjercicio::deserializar(elementoEjercicio, proyecto);
}